package team.star.werespos.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import team.star.werespos.exception.GlobalException;
import team.star.werespos.mapper.OrderDetailMapper;
import team.star.werespos.mapper.OrderMasterMapper;
import team.star.werespos.model.entity.FoodInformation;
import team.star.werespos.model.entity.OrderDetail;
import team.star.werespos.model.entity.OrderMaster;
import team.star.werespos.model.entity.Table;
import team.star.werespos.model.enums.CodeMsgEnum;
import team.star.werespos.model.enums.OrderStatusEnum;
import team.star.werespos.model.enums.TableStatusEnum;
import team.star.werespos.model.enums.TimeRangeEnum;
import team.star.werespos.service.FoodInformationService;
import team.star.werespos.service.OrderService;
import team.star.werespos.service.TableService;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * OrderServiceImpl class<br/>
 *
 * @author hdonghong
 * @since 2019/05/04
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMasterMapper orderMasterMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private TableService tableService;

    @Autowired
    private FoodInformationService foodInformationService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertOne(OrderMaster orderMaster) {
        List<OrderDetail> detailList = orderMaster.getOrderDetailList();
        // 订单项不为空才可以确定是一个新订单
        if (CollectionUtils.isEmpty(detailList)) {
            log.error("【下单】 orderMaster = {}, CodeMsgEnum.ORDER_EMPTY = {}", orderMaster, CodeMsgEnum.ORDER_EMPTY);
            throw GlobalException.create(CodeMsgEnum.ORDER_EMPTY);
        }
        // 餐桌需处于可用餐状态
        Table table = tableService.getByTableNum(orderMaster.getTableNum());
        if (!TableStatusEnum.AVAILABLE.getStatus().equals(table.getTableStatus())) {
            log.error("【下单】 orderMaster = {}, table = {}, CodeMsgEnum.TABLE_UNAVAILABLE = {}", orderMaster, table, CodeMsgEnum.TABLE_UNAVAILABLE);
            throw GlobalException.create(CodeMsgEnum.TABLE_UNAVAILABLE);
        }
        // 订单入库
        Integer result = orderMasterMapper.insert(orderMaster);
        if (result != 1) {
            log.error("【下单】orderMaster = [{}], CodeMsgEnum.DATABASE_EXCEPTION = {}", orderMaster, CodeMsgEnum.DATABASE_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
        // 处理订单项
        BigDecimal orderAmount = addOrderDetail(orderMaster, detailList);
        orderMaster.setOrderAmount(orderAmount);
        orderMasterMapper.updateById(orderMaster);

        // 更新餐桌状态
        table.setTableStatus(TableStatusEnum.USED.getStatus());
        tableService.updateById(table);
    }

    private BigDecimal addOrderDetail(OrderMaster orderMaster, List<OrderDetail> detailList) {
        // 处理订单项，通过订单项菜品id获取菜品列表
        List<Integer> foodIds = detailList.stream()
                .map(OrderDetail::getFoodId)
                .collect(Collectors.toList());
        List<FoodInformation> foodList = foodInformationService.listFood(foodIds);

        // 订单总额
        BigDecimal orderAmount = BigDecimal.ZERO;
        // 将菜品属性复制到订单项中
        Map<Integer, OrderDetail> detailMap = detailList.stream()
                .collect(Collectors.toMap(OrderDetail::getFoodId, orderDetail -> orderDetail));
        for (FoodInformation food : foodList) {
            OrderDetail orderDetail = detailMap.get(food.getFoodId());
            BeanUtils.copyProperties(food, orderDetail, "createTime", "updateTime");
            orderDetail.setOrderId(orderMaster.getOrderId());
            orderDetailMapper.insert(orderDetail);
            orderAmount = orderAmount.add(
                    food.getFoodPrice().multiply(BigDecimal.valueOf(orderDetail.getFoodQuantity())));
        }
        return orderAmount;
    }

    @Override
    public List<OrderMaster> listOrders(Integer orderId, Date startDate, Date endDate) {
        QueryWrapper<OrderMaster> wrapper = new QueryWrapper<>();
        if (orderId != null) {
            wrapper.eq("order_id", orderId);
        } else {
            if (startDate != null) {
                wrapper.gt(true, "create_time", startDate);
            }
            if (endDate != null) {
                endDate.setHours(22);
                endDate.setMinutes(58);
                endDate.setSeconds(58);
                wrapper.lt(true, "create_time", endDate);
            }
        }
        wrapper.orderByDesc("create_time");
        List<OrderMaster> orderList = orderMasterMapper.selectList(wrapper);
        orderList.forEach(this::assembleOrder);
        return orderList;
    }

    @Override
    public void updateById(OrderMaster orderMaster) {
        List<OrderDetail> detailList = orderMaster.getOrderDetailList();
        orderMaster = getOne(orderMaster.getOrderId());
        if (!OrderStatusEnum.NEW.getStatus().equals(orderMaster.getOrderStatus())) {
            log.error("【更新订单】订单不处于可更新状态 orderMaster = [{}]");
            throw GlobalException.create(CodeMsgEnum.ORDER_STATUS_EXCEPTION);
        }
        // 处理订单项，通过订单项菜品id获取菜品列表
        BigDecimal orderAmount = addOrderDetail(orderMaster, detailList);
        orderMaster = new OrderMaster().setOrderId(orderMaster.getOrderId())
                .setOrderAmount(orderMaster.getOrderAmount().add(orderAmount));
        Integer result = orderMasterMapper.updateById(orderMaster);
        if (result != 1) {
            log.error("【更新订单】orderMaster = [{}], CodeMsgEnum.DATABASE_EXCEPTION = {}", orderMaster, CodeMsgEnum.DATABASE_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
    }

    @Override
    public void deleteById(OrderMaster orderMaster) {
        Integer result = orderMasterMapper.deleteById(orderMaster.getOrderId());
        if (result != 1) {
            log.error("【删除订单】orderMaster = [{}], CodeMsgEnum.DATABASE_EXCEPTION = {}",
                    orderMaster, CodeMsgEnum.DATABASE_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
    }

    @Override
    public OrderMaster getOne(Integer orderId) {
        OrderMaster orderMaster = orderMasterMapper.selectById(orderId);
        if (orderMaster == null) {
            log.error("【查看订单】orderId = {}, CodeMsgEnum.ORDER_NOT_EXIST = {}", orderId, CodeMsgEnum.ORDER_NOT_EXIST);
            throw GlobalException.create(CodeMsgEnum.ORDER_NOT_EXIST);
        }
        assembleOrder(orderMaster);
        return orderMaster;
    }

    private void assembleOrder(OrderMaster orderMaster) {
        List<OrderDetail> detailList = orderDetailMapper.selectList(
                new QueryWrapper<OrderDetail>().eq("order_id", orderMaster.getOrderId())
        );
        if (CollectionUtils.isEmpty(detailList)) {
            log.error("【查看订单】 orderMaster = {}, CodeMsgEnum.ORDER_EMPTY = {}", CodeMsgEnum.ORDER_EMPTY);
            throw GlobalException.create(CodeMsgEnum.ORDER_EMPTY);
        }
        orderMaster.setOrderDetailList(detailList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(Integer orderId) {
        OrderMaster orderMaster = getOne(orderId);
        if (!OrderStatusEnum.NEW.getStatus().equals(orderMaster.getOrderStatus())) {
            log.error("【支付订单】orderMaster = [{}], CodeMsgEnum.ORDER_STATUS_EXCEPTION = {}", orderMaster, CodeMsgEnum.ORDER_STATUS_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.ORDER_STATUS_EXCEPTION);
        }
        orderMaster.setOrderStatus(OrderStatusEnum.PAID.getStatus());
        Integer result = orderMasterMapper.updateById(orderMaster);
        if (result != 1) {
            log.error("【支付订单】orderMaster = [{}], CodeMsgEnum.DATABASE_EXCEPTION = {}", orderMaster, CodeMsgEnum.DATABASE_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
        tableService.releaseTable(orderMaster.getTableNum());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Integer orderId) {
        OrderMaster dbOrder = getOne(orderId);
        OrderMaster orderMaster = new OrderMaster()
                .setOrderId(orderId)
                .setOrderStatus(OrderStatusEnum.CANCEL.getStatus());
        Integer result = orderMasterMapper.updateById(orderMaster);
        if (result != 1) {
            log.error("【取消订单】orderMaster = [{}], CodeMsgEnum.DATABASE_EXCEPTION = {}", orderMaster, CodeMsgEnum.DATABASE_EXCEPTION);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
        tableService.releaseTable(dbOrder.getTableNum());
    }

    @Override
    public OrderMaster getByTableNum(Integer tableNum) {
        Integer orderId = getOrderByUsedTable(tableNum);
        return getOne(orderId);
    }

    @Override
    @Transactional
    public void payByTableNum(Integer tableNum) {
        Integer orderId = getOrderByUsedTable(tableNum);
        pay(orderId);
    }

    @Override
    @Transactional
    public void cancelByTableNum(Integer tableNum) {
        Integer orderId = getOrderByUsedTable(tableNum);
        cancel(orderId);
    }

    @Override
    public Map<String, List> listByTimeRange(Integer year, TimeRangeEnum timeRangeEnum) {
        List<Map> amountList;
        List<Map> quantityList;
        if (TimeRangeEnum.DAY.equals(timeRangeEnum)) {
            amountList = orderMasterMapper.getTurnOverByDay(year);
            quantityList = orderDetailMapper.getQuantityByDay(year);
        } else if (TimeRangeEnum.WEEK.equals(timeRangeEnum)) {
            amountList = orderMasterMapper.getTurnOverByWeek(year);
            quantityList = orderDetailMapper.getQuantityByWeek(year);

        } else if (TimeRangeEnum.MONTH.equals(timeRangeEnum)) {
            amountList = orderMasterMapper.getTurnOverByMonth(year);
            quantityList = orderDetailMapper.getQuantityByMonth(year);

        } else {
            amountList = orderMasterMapper.getTurnOverBySeason(year);
            quantityList = orderDetailMapper.getQuantityBySeason(year);

        }
        Map<String, List> resultMap = new HashMap<>();
        resultMap.put("amountList", amountList);
        resultMap.put("quantityList", quantityList);
        return resultMap;
    }

    private Integer getOrderByUsedTable(Integer tableNum) {
        Table table = tableService.getByTableNum(tableNum);
        if (!TableStatusEnum.USED.getStatus().equals(table.getTableStatus())) {
            throw new GlobalException(CodeMsgEnum.TABLE_NO_ORDER);
        }
        OrderMaster orderMaster = orderMasterMapper.selectOne(
                new QueryWrapper<OrderMaster>().eq("table_num", tableNum).eq("order_status", OrderStatusEnum.NEW.getStatus())
        );
        if (orderMaster == null) {
            throw new GlobalException(CodeMsgEnum.ORDER_STATUS_EXCEPTION);
        }
        return orderMaster.getOrderId();
    }
}
